package com.fly.show.controller;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import com.fly.show.model.JsonResult;
import com.fly.core.exception.ValidateException;
import com.fly.core.utils.SpringContextUtils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Api(tags = "tar.gz文件上传、下载接口")
@RestController
@RequestMapping("/file")
@SuppressWarnings("rawtypes")
public class FileController
{
    @Autowired
    RestTemplate restTemplate;
    
    Resource resource = new ClassPathResource("data/nginx-1.25.3.tar.gz");
    
    @ApiOperation("A文件下载")
    @GetMapping(value = "/down", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void down(HttpServletResponse response)
        throws IOException
    {
        String time = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMddHHmmss-");
        response.setHeader("Content-Disposition", "attachment;filename=" + time + resource.getFilename());
        response.setHeader("Cache-Control", "no-store, no-cache");
        try (InputStream input = resource.getInputStream())
        {
            IOUtils.copy(input, response.getOutputStream());
        }
    }
    
    @ApiOperation("B后台下载保存")
    @GetMapping("/server/backDown")
    public JsonResult<?> backDown()
        throws IOException
    {
        String downUrl = SpringContextUtils.getServerBaseURL() + "/file/down";
        ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity(downUrl, byte[].class);
        byte[] body = responseEntity.getBody();
        
        // 数据落地
        File rootDir = new File("upload");
        rootDir.mkdirs();
        File dest = new File(rootDir.getCanonicalPath() + File.separator + RandomStringUtils.randomNumeric(5) + resource.getFilename());
        try (FileOutputStream fos = new FileOutputStream(dest))
        {
            fos.write(body);
        }
        if (SystemUtils.IS_OS_WINDOWS)
        {
            Runtime.getRuntime().exec("cmd /c start " + rootDir.getCanonicalPath());
        }
        return JsonResult.success(dest.getCanonicalPath());
    }
    
    @ApiOperation("B后台转发C")
    @GetMapping("/server/backDownUpload")
    public JsonResult<?> backDownUpload()
        throws IOException
    {
        String downUrl = SpringContextUtils.getServerBaseURL() + "/file/down";
        byte[] bytes = restTemplate.getForEntity(downUrl, byte[].class).getBody();
        
        // 字节流转发到上传接口
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        
        // 转发tar.gz
        Resource byteResource;
        if (RandomUtils.nextBoolean())
        {
            byteResource = new ByteArrayResource(bytes)
            {
                @Override
                public String getFilename()
                {
                    return resource.getFilename();
                }
                
                @Override
                public long contentLength()
                {
                    return bytes.length;
                }
            };
        }
        else
        {
            // 解压tar.gz，寻找html文件
            try (TarArchiveInputStream tis = new TarArchiveInputStream(new GzipCompressorInputStream(new ByteArrayInputStream(bytes))))
            {
                TarArchiveEntry tarEntry;
                while ((tarEntry = tis.getNextTarEntry()) != null)
                {
                    log.info("fileName: {}", tarEntry.getName());
                    if (tarEntry.getName().endsWith(".html"))
                    {
                        break;
                    }
                }
                // 获取html文件 byte[]、fileName
                byte[] tarBytes = IOUtils.toByteArray(tis);
                final String fileName = tarEntry.getName();
                byteResource = new ByteArrayResource(tarBytes)
                {
                    @Override
                    public String getFilename()
                    {
                        return fileName;
                    }
                    
                    @Override
                    public long contentLength()
                    {
                        return tarBytes.length;
                    }
                };
            }
        }
        params.add("file", byteResource);
        params.add("id", "1");
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
        String uploadUrl = SpringContextUtils.getServerBaseURL() + "/file/upload";
        ResponseEntity<JsonResult> responseEntity = restTemplate.postForEntity(uploadUrl, requestEntity, JsonResult.class);
        
        // TODO: upload接口返回的data信息为什么会丢?
        JsonResult result = responseEntity.getBody();
        result.setMessage("上传文件：" + byteResource.getFilename());
        return result;
    }
    
    @ApiOperation("C文件处理")
    @PostMapping("/upload")
    public JsonResult<?> upload(MultipartFile file)
        throws IOException
    {
        if (file == null)
        {
            throw new ValidateException("文件不能为空");
        }
        File dest = new File(new File("upload").getCanonicalPath() + File.separator + file.getOriginalFilename());
        dest.getParentFile().mkdirs();
        file.transferTo(dest);
        if (SystemUtils.IS_OS_WINDOWS)
        {
            Runtime.getRuntime().exec("cmd /c start " + new File("upload").getCanonicalPath());
        }
        return JsonResult.success(dest.getName());
    }
}
